#!/bin/sh

. /usr/share/common

ensure_command "openRTSP"

STREAMER_APP="prudynt"
STREAMER_CONF_FILE="/etc/prudynt.json"

SELF_NAME="$(basename "$0")"

if ! is_streamer_running; then
	echo_error "Streamer is not running"
	exit 1
fi

if is_streamer_disabled; then
	echo_error "Streamer disabled"
	exit 1
fi

hesitate() {
	echo_info "$1"
	sleep 5
	exit 0
}

fix_duration() {
	if [ "$1" -eq 60 ]; then
		echo $(expr "$1" - $(date +%S))
	elif [ $(expr "$1" % 60) -eq 0 ]; then
		m_inc=$(expr "$1" / 60)
		mpart=$(expr "$m_inc" - $(expr $(date +%M) % "$m_inc"))
		echo $(expr "$mpart" "*" 60)
	else
		echo "$1"
	fi
	# TODO: handle cases different than 60 second durations or videos longer than an hour
}

get_free_space() {
	available_space=$(df -k "$record_mount" | sed 1d | tr -d '\n' | awk 'END{print $4}') # in KiB
	echo_info "Space available: $available_space KiB"
}

get_occupied_space() {
	occupied_space=$(du -s "$record_storage" | awk '{print $1}') # in KiB
	echo_info "Space occupied: $occupied_space KiB"
}

# "parameter" "default"
read_config() {
	jct "$STREAMER_CONF_FILE" get "$1" | tr -d '"'
	[ -z "$_" ] || echo "$2"
}

# "path"
remove_oldest_file_in() {
	oldest_file="$(find "$1" -type f -exec ls -ltr {} + | head -n1 | awk '{print $9}')"
	oldest_file_dir="$(dirname $oldest_file)"
	rm -v "$oldest_file"
	[ -z "$(ls -A1 "$oldest_file_dir")" ] && rm -rv "$oldest_file_dir"
}

has_files() {
	[ "$(find "$1" -type f | wc -l)" -gt 0 ]
}

show_help() {
	usage "[<params>]
Where params are:
	-u <string>  RTSP username
	-p <string>  RTSP password
	-c <int>     RTSP stream number
	-h <int>     Frame height
	-w <int>     Frame width
	-f <int>     Frames per second
	-t <int>     Duration in seconds
	-v <str>     Record video format
	-m <path>    Mount point for storing files
	-s <path>    Subdirectory for the device
	-n <string>  File name template (supports strftime format)
	-d <int>     Maximum disk usage, GiB
	-x           One-time run
"
}

singleton "$0"

RECORD_FLAG="/tmp/record.$$"

while getopts "c:d:f:h:m:n:p:s:t:u:v:w:xz:" flag; do
	case "$flag" in
		c) stream_number=$OPTARG ;;
		d) record_limit=$OPTARG ;;
		f) stream_fps=$OPTARG ;;
		h) stream_height=$OPTARG ;;
		m) record_mount=$OPTARG ;;
		n) record_filename=$OPTARG ;;
		p) rtsp_password=$OPTARG ;;
		s) record_device_path=$OPTARG ;;
		t) record_duration=$OPTARG ;;
		u) rtsp_username=$OPTARG ;;
		v) record_videofmt=$OPTARG ;;
		w) stream_width=$OPTARG ;;
		x) one_time="true" ;;
		*) show_help && exit ;;
	esac
done
shift "$((OPTIND - 1))"

record_mount=${record_mount%/}
record_device_path=${record_device_path%/}

if [ -z "$record_mount" ]; then
	hesitate "Mountpoint record_mount is not set"
fi

if ! mountpoint -q "$record_mount"; then
	hesitate "Mountpoint $record_mount is not mounted"
fi

if [ ! -w "$record_mount" ]; then
	hesitate "Mountpoint $record_mount is not writable"
fi

if [ -z "$record_duration" ]; then
	record_duration=10
fi

if [ -z "$record_filename" ]; then
	record_filename="%hostname/%Y/%m/%d/%H-%M-%S"
fi

if [ -z "$record_videofmt" ]; then
	record_videofmt="mp4"
fi

if [ -z "$stream_number" ]; then
	stream_number=0
fi

if [ -z "$stream_width" ]; then
	stream_width=$(read_config stream${stream_number}.width 640)
fi

if [ -z "$stream_height" ]; then
	stream_height=$(read_config stream${stream_number}.height 360)
fi

if [ -z "$stream_fps" ]; then
	stream_fps=$(read_config stream${stream_number}.fps 25)
fi

if [ -z "$rtsp_username" ]; then
	rtsp_username=$(read_config rtsp.username thingino)
fi

if [ -z "$rtsp_password" ]; then
	rtsp_password=$(read_config rtsp.password thingino)
fi

stream_endpoint=$(read_config stream${stream_number}.rtsp_endpoint ch1)
rtsp_stream="rtsp://127.0.0.1/$stream_endpoint"

echo_info "
stream_number: $stream_number
stream_endpoint: $stream_endpoint
stream_fps: $stream_fps
stream_height: $stream_height
stream_width: $stream_width
"

if [ -z "$stream_number" ]; then
	echo_error "Cannot determine stream humber"
fi

if [ -z "$stream_endpoint" ]; then
	echo_error "Cannot determine stream endpoint"
fi

if [ -z "$stream_fps" ]; then
	echo_error "Cannot determine stream fps"
fi

if [ -z "$stream_height" ]; then
	echo_error "Cannot determine stream height"
fi

if [ -z "$stream_width" ]; then
	echo_error "Cannot determine stream width"
fi

case "$record_videofmt" in
	avi) vformat="-i" ;;
	mkv) vformat="-x" ;;
	mov) vformat="-q" ;;
	mp4) vformat="-4" ;;
	  *) echo_error "Unknown video format $record_videofmt"
esac

touch $RECORD_FLAG

record_storage="$record_mount/$record_device_path"
ensure_dir "$record_storage"

record_limit_kb=$((record_limit * 1024 * 1024)) # GiB to KiB
required_space=$((100 * record_duration)) # KiB

while : ; do
	[ -f $RECORD_FLAG ] || break

	get_free_space
	if [ "$available_space" -le "$required_space" ]; then
		echo_info "Space required: $required_space KiB"
		echo_warning "Not enough space: $required_space > $available_space"
		while [ "$available_space" -le "$required_space" ]; do
			remove_oldest_file_in "$record_storage"
			get_free_space
			if ! has_files "$record_storage"; then
				echo_error "$record_mount is empty yet no space!"
				exit 1
			fi
		done
	fi

	if [ "0$record_limit_kb" -gt 0 ]; then
		echo_info "Space limit: $record_limit_kb KiB"
		get_occupied_space
		while [ "$((occupied_space + required_space))" -gt "$record_limit_kb" ]; do
			echo_warning "Occupied space $occupied_space KiB exceeds limit $record_limit_kb KiB"
			remove_oldest_file_in "$record_storage"
			get_occupied_space
			if ! has_files "$record_storage"; then
				echo_error "$record_mount is empty yet no space!"
				exit 1
			fi
		done
	fi

	record_file="$record_storage/$(date +"$record_filename").$record_videofmt"
	ensure_dir "$(dirname $record_file)"

	real_duration=$(fix_duration $record_duration)

	command="openRTSP -V -u $rtsp_username $rtsp_password -w $stream_width -h $stream_height -f $stream_fps -d $real_duration $vformat -b 1048576 -t $rtsp_stream > \"$record_file\""
	echo_command "$command"
	timeout $((real_duration + 5)) sh -c "$command" 2> /dev/null

	[ "true" = "$one_time" ] && rm $RECORD_FLAG
done

echo_warning "Cannot find recording flag $RECORD_FLAG"
[ -n "$LEDD_FLAG" ] && [ -f "$LEDD_FLAG" ] && rm $LEDD_FLAG
echo_info "Exit"

exit 0
